package my.util;

import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;

/**
 * 两个集合进行对比
 * @author xsw
 * @date 2018年12月6日
 */
public class TwoCollectionCompare<NewObject,OldObject> {
	
	private Map<Object,NewObject> newMap;
	private Map<Object,OldObject> oldMap;
	
	private Collection<NewObject> newCollection;
	private Collection<OldObject> oldCollection;
	
	private ObjectIndex<NewObject> newIndex;
	private ObjectIndex<OldObject> oldIndex;
	
	private ObjectCompare<NewObject,OldObject> objectCompare;
	
	/**
	 * 默认构造器，使用自身对象作为索引，以自身对象比较
	 * @param newCollection 新集合
	 * @param oldCollection 旧集合
	 */
	public TwoCollectionCompare(Collection<NewObject> newCollection, Collection<OldObject> oldCollection) {
		this(newCollection, oldCollection, null, null, null);
	}
	
	/**
	 * 自定义构造器，设置自定义索引
	 * @param newCollection 新集合
	 * @param oldCollection 旧集合
	 * @param newIndex 新对象索引
	 * @param oldIndex 旧对象索引
	 */
	public TwoCollectionCompare(Collection<NewObject> newCollection, Collection<OldObject> oldCollection,
			ObjectIndex<NewObject> newIndex,ObjectIndex<OldObject> oldIndex) {
		this(newCollection, oldCollection, newIndex, oldIndex, null);
	}
	
	/**
	 * 自定义构造器，设置自定义索引，设置自定义比较器
	 * @param newCollection 新集合
	 * @param oldCollection 旧集合
	 * @param newIndex 新对象索引
	 * @param oldIndex 旧对象索引
	 * @param objectCompare 自定义比较器
	 */
	public TwoCollectionCompare(Collection<NewObject> newCollection, Collection<OldObject> oldCollection,
			ObjectIndex<NewObject> newIndex,ObjectIndex<OldObject> oldIndex,ObjectCompare<NewObject,OldObject> objectCompare) {
		if(newCollection == null || oldCollection == null ){
			throw new NullPointerException();
		}
		if(newIndex == null){//为null则默认使用自身对象作为index
			newIndex = new DefaultIndex<NewObject>();
		}
		if(oldIndex == null){
			oldIndex = new DefaultIndex<OldObject>();
		}
		if(objectCompare == null){//使用默认比较器
			objectCompare = new DefaultObjectCompare<NewObject,OldObject>();
		}
		
		this.newCollection = newCollection;
		this.oldCollection = oldCollection;
		this.newIndex = newIndex;
		this.oldIndex = oldIndex;
		this.objectCompare = objectCompare;
		initMap();
	}
	
	/**
	 * 初始化map，将集合数据按照索引放入map中
	 */
	private void initMap(){
		newMap = new HashMap<Object,NewObject>();
		oldMap = new HashMap<Object,OldObject>();
		for (NewObject a : newCollection) {
			newMap.put(newIndex.getIndex(a), a);
		}
		for (OldObject b : oldCollection) {
			oldMap.put(oldIndex.getIndex(b), b);
		}
	}
	
	/**
	 * 添加老元素
	 * @param oldObject
	 */
	public void addOldObject(OldObject oldObject){
		oldCollection.add(oldObject);
		oldMap.put(oldIndex.getIndex(oldObject), oldObject);
	}
	
	/**
	 * 寻找新数组中的新元素，即：在老数组中找不到对应索引的元素
	 * @return
	 */
	public Collection<NewObject> getNewList(){
		Collection<NewObject> list = new LinkedList<NewObject>();
		for (NewObject a : newCollection) {
			if(getOldElementByNewIdex(a) == null){
				list.add(a);
			}
		}
		return list;
	}
	
	/**
	 * 寻找旧元素，即旧数组中的索引在在新数组中找不到
	 * @return
	 */
	public Collection<OldObject> getLoseByOldList(){
		Collection<OldObject> list = new LinkedList<OldObject>();
		for (OldObject b : oldCollection) {
			if(getNewElementByOldIndex(b) == null){
				list.add(b);
			}
		}
		return list;
	}
	
	/**
	 * 寻找状态发生变化的旧元素
	 * @return
	 */
	public Map<OldObject,NewObject> getStateChangeMap(){
		Map<OldObject,NewObject> map = new HashMap<OldObject,NewObject>();
		for (OldObject old : oldCollection) {
			NewObject newObject = getNewElementByOldIndex(old);
			if(newObject == null)
				continue;
			if(!objectCompare.compare(newObject, old)){//两个对象比较不一致，即：状态发生了变化
				map.put(old, newObject);
			}
		}
		return map;
	}
	
	/**
	 * 寻找状态发生变化的旧元素，并将变化的数据填充到就元素中
	 * @return
	 */
	public Collection<OldObject> getStateChangeList(){
		Collection<OldObject> list = new LinkedList<OldObject>();
		for (OldObject old : oldCollection) {
			NewObject newObject = getNewElementByOldIndex(old);
			if(newObject == null)
				continue;
			if(!objectCompare.compare(newObject, old)){//两个对象比较不一致，即：状态发生了变化
				BeanUtil.copyIgnoreNull(newObject, old);
				list.add(old);
			}
		}
		return list;
	}
	
	/**
	 * 根据新元素寻找老元素对象
	 * @param newObject
	 * @return
	 */
	public OldObject getOldElementByNewIdex(NewObject newObject){
		return oldMap.get(newIndex.getIndex(newObject));
	}
	
	/**
	 * 根据老元素寻找新元素对象
	 * @param oldObject
	 * @return
	 */
	public NewObject getNewElementByOldIndex(OldObject oldObject){
		return newMap.get(oldIndex.getIndex(oldObject));
	}
	
	/**
	 * 默认索引，返回自身对象
	 * @author xsw
	 * @date 2018年12月7日
	 * @param <T>
	 */
	static class DefaultIndex<T> implements ObjectIndex<T>{
		@Override
		public Object getIndex(T t) {
			return t;
		}
	}
	
	/**
	 * 对象索引获取接口
	 * @author xsw
	 * @date 2018年12月7日
	 * @param <T>
	 */
	public static interface ObjectIndex<T>{
		/**
		 * 获取对象索引
		 * @param t
		 * @return
		 */
		Object getIndex(T t);
	}

	/**
	 * 默认对象比较器
	 * @author xsw
	 * @date 2018年12月7日
	 * @param <NewObject>
	 * @param <OldObject>
	 */
	static class DefaultObjectCompare<NewObject,OldObject> implements ObjectCompare<NewObject,OldObject>{

		@Override
		public boolean compare(NewObject newObject, OldObject oldObject) {
			if(newObject == oldObject)
				return true;
			//两个都等于null，或两个对象equals相等
			return newObject == null ? oldObject == null : newObject.equals(oldObject);
		}
		
	}
	
	/**
	 * 对象比较接口
	 * @author xsw
	 * @date 2018年12月7日
	 * @param <NewObject>
	 * @param <OldObject>
	 */
	public static interface ObjectCompare<NewObject,OldObject>{
		/**
		 * 比较两个对象是否相等
		 * @param newObject 新对象
		 * @param oldObject 旧对象
		 * @return
		 */
		boolean compare(NewObject newObject,OldObject oldObject);
	}
	
}
